///*
// * Copyright (C) 2007-2016 Artima, Inc. All rights reserved.
// *
// * Licensed under the Apache License, Version 2.0 (the "License");
// * you may not use this file except in compliance with the License.
// * You may obtain a copy of the License at
// *
// *     http://www.apache.org/licenses/LICENSE-2.0
// *
// * Unless required by applicable law or agreed to in writing, software
// * distributed under the License is distributed on an "AS IS" BASIS,
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// * See the License for the specific language governing permissions and
// * limitations under the License.
// *
// * Example code from:
// *
// * Programming in Scala, Third Edition
// * by Martin Odersky, Lex Spoon, Bill Venners
// *
// * http://booksites.artima.com/programming_in_scala_3ed
// */
//
////compile this along with ../composition-and-inheritance/LayoutElement.scala
//
//  package org.stairwaybook.expr
//  import org.stairwaybook.layout.Element.elem
//
//  sealed abstract class Expr
//  case class Var(name: String) extends Expr
//  case class Number(num: Double) extends Expr
//  case class UnOp(operator: String, arg: Expr) extends Expr
//  case class BinOp(operator: String,
//      left: Expr, right: Expr) extends Expr
//
//  class ExprFormatter {
//
//    // Contains operators in groups of increasing precedence
//    private val opGroups =
//      Array(
//        Set("|", "||"),
//        Set("&", "&&"),
//        Set("^"),
//        Set("==", "!="),
//        Set("<", "<=", ">", ">="),
//        Set("+", "-"),
//        Set("*", "%")
//      )
//
//    // A mapping from operators to their precedence
//    private val precedence = {
//      val assocs =
//        for {
//          i <- 0 until opGroups.length
//          op <- opGroups(i)
//        } yield op -> i
//      assocs.toMap
//    }
//
//    private val unaryPrecedence = opGroups.length
//    private val fractionPrecedence = -1
//
//    // continued in Listing 15.21...
//
//  import org.stairwaybook.layout.Element
//
//  // ...continued from Listing 15.20
//
//  import org.stairwaybook.layout.Element
//
//  private def format(e: Expr, enclPrec: Int): Element =
//
//    e match {
//
//      case Var(name) =>
//        elem(name)
//
//      case Number(num) =>
//        def stripDot(s: String) =
//          if (s endsWith ".0") s.substring(0, s.length - 2)
//          else s
//        elem(stripDot(num.toString))
//
//      case UnOp(op, arg) =>
//        elem(op) beside format(arg, unaryPrecedence)
//
//      case BinOp("/", left, right) =>
//        val top = format(left, fractionPrecedence)
//        val bot = format(right, fractionPrecedence)
//        val line = elem('-', top.width max bot.width, 1)
//        val frac = top above line above bot
//        if (enclPrec != fractionPrecedence) frac
//        else elem(" ") beside frac beside elem(" ")
//
//      case BinOp(op, left, right) =>
//        val opPrec = precedence(op)
//        val l = format(left, opPrec)
//        val r = format(right, opPrec + 1)
//        val oper = l beside elem(" " + op + " ") beside r
//        if (enclPrec <= opPrec) oper
//        else elem("(") beside oper beside elem(")")
//    }
//
//    def format(e: Expr): Element = format(e, 0)
//  }
